package com.inkyi.audition;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 1.获取目录下所有的文件
 * 2.获取后缀为Java的文件
 * 3.按行读取文件，
 * 过滤空行，匹配注解，注意大括号等符号，
 *
 * 要求：
 * 1.统计代码行数
 * 2.统计注释行数
 * 3.统计空行数
 *
 */
public class CheckCodeMian {

    /**
     * 行尾注释
     * 行内注释,容易和字符串混合，不容易识别
     * [{};](\s+)?([//|/\*|/\*\*]?.*)
     */
    private static Pattern lineEndNotPat = Pattern.compile("[{};](\\s+)?([//|/\\*|/\\*\\*]?.*)");


    public static void main(String[] args) throws InterruptedException {
        // 拿到所有的需要统计的文件
        String rootPath = "D:/git/blog-example/";
        List<String> allFiles = new ArrayList<>();
        findJavaFiles(rootPath,allFiles);
        manyThread(allFiles);
//        singleThread(allFiles);

    }

    public static void manyThread(List<String> allFiles) throws InterruptedException {

        Map<String, AtomicInteger> countMap = new ConcurrentHashMap<>();
        {
            countMap.put("code", new AtomicInteger(0)); //
            countMap.put("note",new AtomicInteger(0));
            countMap.put("empty",new AtomicInteger(0));
        }
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        for (String filePaht : allFiles) {
            executorService.submit(()->{
                try {
                    System.out.println(filePaht);
                    Map<String, Integer> map = statisticsCode(filePaht);
                    printlnMap(map);
                    map.forEach((k,v)->{
                        countMap.get(k).addAndGet(v);
                    });
                }catch (RuntimeException e){
                    e.printStackTrace();
                    System.out.println("遇到一场，不要中断统计:" + e.getMessage());
                }
            });
        }

        executorService.shutdown();
        if(executorService.awaitTermination(10, TimeUnit.MINUTES)){
            System.out.println("--------------执行完成");
        }

        printlnMap(countMap);

    }

    public static void singleThread(List<String> allFiles) {

        // 统计每个文件的代码数量
        Map<String,Integer> totalMap = new HashMap<>();
        for (String filePaht : allFiles) {
            try {
                System.out.println(filePaht);
                Map<String, Integer> map = statisticsCode(filePaht);
                map.forEach((k,v)->{
                    totalMap.merge(k,v,Integer::sum);
                });
                printlnMap(totalMap);
            }catch (RuntimeException e){
                System.out.println("遇到一场，不要中断统计:" + e.getMessage());
            }
        }

        printlnMap(totalMap);
    }

    /**
     * 统计代码
     *
     * @param filePath 文件路径
     * @return {@link Map}<{@link String}, {@link Integer}>
     */
    private static Map<String, Integer> statisticsCode(String filePath) {
        File codeFile = new File(filePath);

        if(!codeFile.exists() || !codeFile.isFile() || !codeFile.getName().endsWith(".java")){
            return Collections.emptyMap();
        }
        Map<String,Integer> codeMap = new HashMap<>();

        try (FileInputStream fis = new FileInputStream(codeFile);
             InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
             BufferedReader br = new BufferedReader(isr)) {
            String line;
            boolean manyNoteFlag = false;
            while((line = br.readLine()) != null) {
                line = line.trim();
                // 空行
                if(line.isEmpty()){
                    codeMap.merge("empty", 1, Integer::sum);
                }
                // 单行注释
                else if(line.startsWith("//")){
                    codeMap.merge("note", 1, Integer::sum);
                }
                // 多行注释 - 开始
                else if(line.startsWith("/*")){
                    manyNoteFlag = true;
                    codeMap.merge("note", 1, Integer::sum);
                }
                // 多行注释 - 结束
                else if(line.endsWith("*/")){
                    manyNoteFlag = false;
                    codeMap.merge("note", 1, Integer::sum);
                }
                else if(manyNoteFlag){
                    codeMap.merge("note", 1, Integer::sum);
                }
                //代码
                else {
//                    if(line.equals("}")){
//                        continue;
//                    }
                    codeMap.merge("code", 1, Integer::sum);
                    //行尾注释
                    Matcher matcher = lineEndNotPat.matcher(line);
                    if (matcher.find() && !matcher.group(2).isEmpty()) {
                        codeMap.merge("note", 1, Integer::sum);
                    }
                    System.out./*fasfasdfdasfds*/println(); /**dfsafsdafdasfd
                     dfasfsadfsdajfkdjsakl;fdlk;sajfkl;djsa;klfjdls;ajfadkls;
                     */
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("统计错误:" + e.getMessage());
        }
        return codeMap;
    }


    /**
     * 找到java文件
     *
     * @param currPath  根路径
     * @param filePaths 文件路径
     */
    private static void findJavaFiles(String currPath, List<String> filePaths) {
        File rootFile = new File(currPath);
        if(!rootFile.exists()){
            return;
        }
        File[] files = rootFile.listFiles();
        if(files == null || files.length == 0){
            return;
        }
        for (File file : files) {
            if(file.isFile() && file.getName().endsWith(".java")){
                filePaths.add(file.getPath());
            }else if(file.isDirectory()){
                findJavaFiles(file.getPath(),filePaths);
            }
        }
    }

    private static void printlnMap(Map<String,?> map){
        if(map == null || map.isEmpty()){
            return;
        }
        map.forEach((k,v)->{
            System.out.println(k + "---" + v);
        });
        System.out.println("-------------------");
    }
}
